Completed
Push — master ( 641a91...fc9f6a )
by
unknown
10:16
created

angular.service(ꞌCredentialServiceꞌ)   B

Complexity

Conditions 1
Paths 6

Size

Total Lines 329

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
dl 0
loc 329
rs 7
c 0
b 0
f 0
nc 6
nop 4

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
/**
2
 * Nextcloud - passman
3
 *
4
 * @copyright Copyright (c) 2016, Sander Brand ([email protected])
5
 * @copyright Copyright (c) 2016, Marcos Zuriaga Miguel ([email protected])
6
 * @license GNU AGPL version 3 or any later version
7
 *
8
 * This program is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Affero General Public License as
10
 * published by the Free Software Foundation, either version 3 of the
11
 * License, or (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU Affero General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Affero General Public License
19
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
 *
21
 */
22
23
(function () {
24
	'use strict';
25
	/**
26
	 * @ngdoc service
27
	 * @name passmanApp.CredentialService
28
	 * @description
29
	 * # CredentialService
30
	 * Service in the passmanApp.
31
	 */
32
	angular.module('passmanApp')
33
		.service('CredentialService', ['$http', 'EncryptService', 'VaultService', 'FileService', function ($http, EncryptService, VaultService, FileService) {
34
			var credential = {
35
				'credential_id': null,
36
				'guid': null,
37
				'vault_id': null,
38
				'label': null,
39
				'description': null,
40
				'created': null,
41
				'changed': null,
42
				'tags': [],
43
				'email': null,
44
				'icon':{
45
					'type': false,
46
					'content': ''
47
				},
48
				'username': null,
49
				'password': null,
50
				'url': null,
51
				'favicon': null,
52
				'renew_interval': null,
53
				'expire_time': 0,
54
				'delete_time': 0,
55
				'files': [],
56
				'custom_fields': [],
57
				'otp': {},
58
				'hidden': false
59
			};
60
			var _encryptedFields = ['description', 'username', 'password', 'files', 'custom_fields', 'otp', 'email', 'tags', 'url'];
61
62
63
			return {
64
				newCredential: function () {
65
					return angular.copy(credential);
66
				},
67
				createCredential: function (credential) {
68
					var _credential = angular.copy(credential);
69
					for (var i = 0; i < _encryptedFields.length; i++) {
70
						var field = _encryptedFields[i];
71
						var fieldValue = angular.copy(credential[field]);
72
						_credential[field] = EncryptService.encryptString(JSON.stringify(fieldValue));
73
					}
74
75
					_credential.expire_time = new Date(angular.copy(credential.expire_time)).getTime() / 1000;
76
77
					var queryUrl = OC.generateUrl('apps/passman/api/v2/credentials');
78
					return $http.post(queryUrl, _credential).then(function (response) {
79
						if (response.data) {
80
							return response.data;
81
						} else {
82
							return response;
83
						}
84
					});
85
				},
86
				getEncryptedFields: function () {
87
					return _encryptedFields;
88
				},
89
				updateCredential: function (credential, skipEncryption, key) {
90
					var _credential = angular.copy(credential);
91
					if (!skipEncryption) {
92
						for (var i = 0; i < _encryptedFields.length; i++) {
93
							var field = _encryptedFields[i];
94
							var fieldValue = angular.copy(credential[field]);
95
							_credential[field] = EncryptService.encryptString(JSON.stringify(fieldValue), key);
96
						}
97
					}
98
					_credential.expire_time = new Date(angular.copy(credential.expire_time)).getTime() / 1000;
99
100
					var queryUrl = OC.generateUrl('apps/passman/api/v2/credentials/' + credential.guid);
101
					return $http.patch(queryUrl, _credential).then(function (response) {
102
						if (response.data) {
103
							return response.data;
104
						} else {
105
							return response;
106
						}
107
					});
108
				},
109
				getCredential: function (guid) {
110
					var queryUrl = OC.generateUrl('apps/passman/api/v2/credentials/' + guid);
111
					return $http.get(queryUrl).then(function (response) {
112
						if (response.data) {
113
							return response.data;
114
						} else {
115
							return response;
116
						}
117
					});
118
				},
119
				destroyCredential: function (guid) {
120
					var queryUrl = OC.generateUrl('apps/passman/api/v2/credentials/' + guid);
121
					return $http.delete(queryUrl).then(function (response) {
122
						if (response.data) {
123
							return response.data;
124
						} else {
125
							return response;
126
						}
127
					});
128
				},
129
				encryptCredential: function (credential, key) {
130
					for (var i = 0; i < _encryptedFields.length; i++) {
131
						var field = _encryptedFields[i];
132
						var fieldValue = angular.copy(credential[field]);
133
						credential[field] = EncryptService.encryptString(JSON.stringify(fieldValue), key);
134
					}
135
					return credential;
136
				},
137
				decryptCredential: function (credential, key) {
138
					for (var i = 0; i < _encryptedFields.length; i++) {
139
						var field = _encryptedFields[i];
140
						var fieldValue = angular.copy(credential[field]);
141
						var field_decrypted_value;
142
						try {
143
							field_decrypted_value = EncryptService.decryptString(fieldValue, key);
144
						} catch (e) {
145
							throw e;
146
						}
147
						try {
148
							credential[field] = JSON.parse(field_decrypted_value);
149
						} catch (e) {
150
							console.warn('Field' + field + ' in ' + credential.label + ' could not be parsed! Value:' + fieldValue);
151
152
						}
153
154
					}
155
					return credential;
156
				},
157
				getSharedKeyFromCredential: function (credential) {
158
					var key = null;
159
					if (!credential.hasOwnProperty('acl') && credential.hasOwnProperty('shared_key')) {
160
						if (credential.shared_key) {
161
							key = EncryptService.decryptString(angular.copy(credential.shared_key));
162
						}
163
					}
164
					if (credential.hasOwnProperty('acl')) {
165
						key = EncryptService.decryptString(angular.copy(credential.acl.shared_key));
166
					}
167
					return key;
168
				},
169
				getRevisions: function (guid) {
170
					var queryUrl = OC.generateUrl('apps/passman/api/v2/credentials/' + guid + '/revision');
171
					return $http.get(queryUrl).then(function (response) {
172
						if (response.data) {
173
							return response.data;
174
						} else {
175
							return response;
176
						}
177
					});
178
				},
179
				updateRevision: function (revision) {
180
					var _revision = angular.copy(revision);
181
					_revision.credential_data = window.btoa(JSON.stringify(_revision.credential_data));
182
					var queryUrl = OC.generateUrl('apps/passman/api/v2/credentials/' + revision.credential_data.guid + '/revision/' + revision.revision_id);
183
					return $http.patch(queryUrl, _revision).then(function (response) {
184
						if (response.data) {
185
							return response.data;
186
						} else {
187
							return response;
188
						}
189
					});
190
				},
191
				deleteRevision: function (credential_guid, revision_id) {
192
					var queryUrl = OC.generateUrl('apps/passman/api/v2/credentials/' + credential_guid + '/revision/' + revision_id);
193
					return $http.delete(queryUrl).then(function (response) {
194
						if (response.data) {
195
							return response.data;
196
						} else {
197
							return response;
198
						}
199
					});
200
				},
201
				reencryptCredential: function (credential_guid, old_password, new_password, skipSharingKey) {
202
203
					var service = this;
204
205
					var progress_datatype = function (current, total, process) {
206
						this.process = process;
207
						this.current = current;
208
						this.total = total;
209
						this.calculated = current / total * 100;
210
					};
211
212
					var promise_credential_update = function () {
213
						service.getCredential(credential_guid).then((function (credential) {
214
							this.parent.plain_credential = service.decryptCredential(credential, this.parent.old_password);
215
							var tmp = angular.copy(this.parent.plain_credential);
216
217
							if (tmp.hasOwnProperty('shared_key') && tmp.shared_key !== null && !skipSharingKey) {
218
								var shared_key = EncryptService.decryptString(angular.copy(tmp.shared_key)).trim();
219
								tmp.shared_key = EncryptService.encryptString(angular.copy(shared_key), this.parent.new_password);
220
								tmp.set_share_key = true;
221
								tmp.skip_revision = true;
222
								this.parent.new_password = shared_key;
223
							}
224
225
							this.parent.new_credential_cryptogram = service.encryptCredential(tmp, this.parent.new_password);
226
							this.call_progress(new progress_datatype(1, 2, 'credential'));
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like progress_datatype should be capitalized.
Loading history...
227
228
							// Save data
229
							this.parent.new_credential_cryptogram.skip_revision = true;
230
							service.updateCredential(this.parent.new_credential_cryptogram, true).then((function () {
231
								this.call_progress(new progress_datatype(2, 2, 'credential'));
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like progress_datatype should be capitalized.
Loading history...
232
								this.call_then({
233
									plain_text: this.parent.plain_credential,
234
									cryptogram: this.parent.new_credential_cryptogram
235
								});
236
							}).bind(this));
237
						}).bind(this));
238
					};
239
240
					var promise_files_update = function () {
241
						// Add the double of the files so we take encryption phase and upload to the server into the math
242
						this.total = this.parent.plain_credential.files.length * 2;	 // Binded on credential finish upload
243
						this.current = 0;
244
245
						for (var i = 0; i < this.parent.plain_credential.files.length; i++) {
246
							var _file = this.parent.plain_credential.files[i];
247
							/* jshint ignore:start */
248
							FileService.getFile(_file).then((function (fileData) {
249
								//Decrypt with old key
250
								fileData.filename = EncryptService.decryptString(fileData.filename, this.parent.old_password);
251
								fileData.file_data = EncryptService.decryptString(fileData.file_data, this.parent.old_password);
252
253
								this.current++;
254
255
								this.call_progress(new progress_datatype(this.current, this.total, 'files'));
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like progress_datatype should be capitalized.
Loading history...
256
257
								FileService.updateFile(fileData, this.parent.new_password).then((function () {
258
									this.current++;
259
									this.call_progress(new progress_datatype(this.current, this.total, 'files'));
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like progress_datatype should be capitalized.
Loading history...
260
									if (this.current === this.total) {
261
										this.call_then('All files has been updated');
262
									}
263
								}).bind(this));
264
							}).bind(this));
265
							/* jshint ignore:end */
266
						}
267
						if (this.parent.plain_credential.files.length === 0) {
268
							this.call_progress(new progress_datatype(0, 0, 'files'));
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like progress_datatype should be capitalized.
Loading history...
269
							this.call_then("No files to update");
270
						}
271
					};
272
273
					var promise_revisions_update = function () {
274
						service.getRevisions(this.parent.plain_credential.guid).then((function (revisions) {
275
							// Double, so we include the actual upload of the data back to the server
276
							this.total = revisions.length * 2;
277
							this.upload = 0;
278
							this.current = 0;
279
							this.revisions = revisions;
280
281
							var revision_workload = function () {
282
								if (this.revisions.length === 0) {
283
									this.call_progress(new progress_datatype(0, 0, 'revisions'));
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like progress_datatype should be capitalized.
Loading history...
284
									this.call_then("No history to update");
285
									return;
286
								}
287
								var _revision = revisions[this.current];
288
								//Decrypt!
289
								_revision.credential_data = service.decryptCredential(_revision.credential_data, this.parent.old_password);
290
								_revision.credential_data = service.encryptCredential(_revision.credential_data, this.parent.new_password);
291
								this.current++;
292
293
								this.call_progress(new progress_datatype(this.current + this.upload, this.total, 'revisions'));
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like progress_datatype should be capitalized.
Loading history...
294
295
								service.updateRevision(_revision).then((function () {
296
									this.upload++;
297
									this.call_progress(new progress_datatype(this.upload + this.current, this.total, 'revisions'));
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like progress_datatype should be capitalized.
Loading history...
298
									if (this.current + this.upload === this.total) {
299
										this.call_then("History updated");
300
									}
301
								}).bind(this));
302
303
								if (this.current !== (this.total / 2)) {
304
									setTimeout(revision_workload.bind(this), 1);
305
								}
306
							};
307
							setTimeout(revision_workload.bind(this), 1);
308
						}).bind(this));
309
					};
310
311
					var promise_workload = function () {
312
						this.old_password = angular.copy(old_password);
313
						this.new_password = angular.copy(new_password);
314
						this.promises = 0;
315
316
						var master_promise = this;
317
318
						var password_data = function () {
319
							this.old_password = master_promise.old_password;
320
							this.new_password = master_promise.new_password;
321
							this.plain_credential = master_promise.plain_credential;
322
						};
323
						this.credential_data = {};
324
						/** global: C_Promise */
325
						(new C_Promise(promise_credential_update, new password_data())).progress(function (data) {
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like password_data should be capitalized.
Loading history...
326
							master_promise.call_progress(data);
327
						}).then(function (data) {
328
							console.warn("End credential update");
329
							master_promise.plain_credential = data.plain_text;
330
							master_promise.promises++;
331
332
							master_promise.credential_data = data;
333
							/** global: C_Promise */
334
							(new C_Promise(promise_files_update, new password_data())).progress(function (data) {
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like password_data should be capitalized.
Loading history...
335
								master_promise.call_progress(data);
336
							}).then(function () {
337
								console.warn("End files update");
338
								master_promise.promises--;
339
								if (master_promise.promises === 0) {
340
									master_promise.call_then(master_promise.credential_data);
341
								}
342
							});
343
344
							master_promise.promises++;
345
							/** global: C_Promise */
346
							(new C_Promise(promise_revisions_update, new password_data())).progress(function (data) {
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like password_data should be capitalized.
Loading history...
347
								master_promise.call_progress(data);
348
							}).then(function () {
349
								console.warn("End revisions update");
350
								master_promise.promises--;
351
								if (master_promise.promises === 0) {
352
									master_promise.call_then(master_promise.credential_data);
353
								}
354
							});
355
						});
356
					};
357
					/** global: C_Promise */
358
					return new C_Promise(promise_workload);
359
				}
360
			};
361
		}]);
362
}());